﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using Velocity4Net.Ctx;

namespace Velocity4Net
{

    /*
     * Licensed to the Apache Software Foundation (ASF) under one
     * or more contributor license agreements.  See the NOTICE file
     * distributed with this work for additional information
     * regarding copyright ownership.  The ASF licenses this file
     * to you under the Apache License, Version 2.0 (the
     * "License"); you may not use this file except in compliance
     * with the License.  You may obtain a copy of the License at
     *
     *   http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing,
     * software distributed under the License is distributed on an
     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     * KIND, either express or implied.  See the License for the
     * specific language governing permissions and limitations
     * under the License.
     */







    /**
     *  General purpose implementation of the application Context
     *  interface for general application use.  This class should
     *  be used in place of the original Context class.
     *
     *  This implementation uses a HashMap  (@see java.util.HashMap )
     *  for data storage.
     *
     *  This context implementation cannot be shared between threads
     *  without those threads synchronizing access between them, as
     *  the HashMap is not synchronized, nor are some of the fundamentals
     *  of AbstractContext.  If you need to share a Context between
     *  threads with simultaneous access for some reason, please create
     *  your own and extend the interface Context
     *
     *  @see org.apache.velocity.context.Context
     *
     *  @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
     *  @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
     *  @author <a href="mailto:fedor.karpelevitch@home.com">Fedor Karpelevitch</a>
     *  @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
     *  @version $Id: VelocityContext.java 1780734 2017-01-28 19:21:08Z cbrisson $
     */
    public class VelocityContext : AbstractContext, ICloneable
    {
        /**
         * Version Id for serializable
         */
        private const long serialVersionUID = 9033846851064645037L;

        /**
         *  Storage for key/value pairs.
         */
        private IDictionary<String, Object> context = null;

        /**
         *  Creates a new instance (with no inner context).
         */
        public VelocityContext() : this(null, null)
        {
        }

        /**
         *  Creates a new instance with the provided storage (and no inner
         *  context).
         * @param context
         */
        public VelocityContext(IDictionary<String, Object> context) : this(context, null)
        {
        }

        /**
         *  Chaining constructor, used when you want to
         *  wrap a context in another.  The inner context
         *  will be 'read only' - put() calls to the
         *  wrapping context will only effect the outermost
         *  context
         *
         *  @param innerContext The <code>Context</code> implementation to
         *  wrap.
         */
        public VelocityContext(Context innerContext) : this(null, innerContext)
        {

        }

        /**
         *  Initializes internal storage (never to <code>null</code>), and
         *  inner context.
         *
         *  @param context Internal storage, or <code>null</code> to
         *  create default storage.
         *  @param innerContext Inner context.
         */
        public VelocityContext(IDictionary<String, Object> context, Context innerContext) : base(innerContext)
        {
            this.context = (context == null ? new Dictionary<String, Object>() : context);
        }

        /**
         *  retrieves value for key from internal
         *  storage
         *
         *  @param key name of value to get
         *  @return value as object
         */
        public override Object internalGet(String key)
        {
            return context[key];
        }

        /**
         *  stores the value for key to internal
         *  storage
         *
         *  @param key name of value to store
         *  @param value value to store
         *  @return previous value of key as Object
         */
        public override Object internalPut(String key, Object value)
        {
            context.Add(key, value);
            return value;
        }

        /**
         *  determines if there is a value for the
         *  given key
         *
         *  @param key name of value to check
         *  @return true if non-null value in store
         */
        public override bool internalContainsKey(String key)
        {
            return context.ContainsKey(key);
        }

        /**
         *  returns array of keys
         *
         *  @return keys as []
         */
        public override String[] internalGetKeys()
        {
            return context.Keys.ToArray();
        }

        /**
         *  remove a key/value pair from the
         *  internal storage
         *
         *  @param key name of value to remove
         *  @return value removed
         */
        public override Object internalRemove(String key)
        {
            return context.Remove(key);
        }

        /**
         * Clones this context object.
         *
         * @return A shallow copy of this <code>Context</code>.
         */

        public object Clone()
        {
            VelocityContext clone = null;
            try
            {
                clone = (VelocityContext)base.MemberwiseClone();
                clone.context = new Dictionary<string, object>(context);
            }
            catch (Exception ignored)
            {
            }
            return clone;
        }
    }
}